package org.zhangsan.beans;

import lombok.Getter;
import lombok.Setter;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zhangsan.beans.lock.AbstractZookeeperLock;

/**
 * @ClassName ZookeeperClient
 * @Description // 分布式锁客户端
 * @Author singleZhang
 * @Email 405780096@qq.com
 * @Date 2020/12/8 0008 下午 3:03
 **/
public class ZookeeperClient {
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperClient.class);

    private static final int SLEEP_TIME = 1000;
    private static final int MAX_RETRIES = 3;

    @Getter @Setter
    private String zookeeperServer;
    @Getter @Setter
    private String zookeeperLockPath;

    @Getter
    private CuratorFramework client;

    public ZookeeperClient(String zookeeperServer, String zookeeperLockPath) {
        this.zookeeperServer = zookeeperServer;
        this.zookeeperLockPath = zookeeperLockPath;
    }

    public <T> T lock(AbstractZookeeperLock<T> mutex) {
        String path = this.getZookeeperLockPath() + mutex.getLockPath();
        InterProcessMutex lock = new InterProcessMutex(this.getClient(), path); //创建锁对象
        boolean success = false;
        try {
            try {
                success = lock.acquire(mutex.getTimeout(), mutex.getTimeUnit()); //获取锁
            } catch (Exception e) {
                throw new RuntimeException("obtain lock error " + e.getMessage() + ", path " + path);
            }
            if (success) {
                return (T) mutex.execute();
            } else {
                return null;
            }
        } finally {
            try {
                if (success){
                    lock.release(); //释放锁
                }
            } catch (Exception e) {
                logger.error("release lock error {}, path {}", e.getMessage(), path);
            }
        }
    }

    public void init() {
        this.client = CuratorFrameworkFactory
                .builder()
                .connectString(this.getZookeeperServer())
                .retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME, MAX_RETRIES))
                .build();
        this.client.start();
    }

    public void destroy() {
        try {
            if (getClient() != null) {
                getClient().close();
            }
        } catch (Exception e) {
            logger.error("stop zookeeper client error {}", e.getMessage());
        }
    }

    /**
     * 分布式ID生成
     * */
    public String makeId(String nodeName) {
        String str = createSeqNode(nodeName);
        if (null == str) {
            return null;
        }
        int index = str.lastIndexOf(nodeName);
        if (index >= 0) {
            index += nodeName.length();
            return index <= str.length() ? str.substring(index) : "";
        }
        return str;
    }

    /**
     * 创建顺序节点
     * */
    private String createSeqNode(String pathPrefix) {
        try {
            // 创建一个 ZNode 顺序节点
            String s = client.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    //避免zookeeper的顺序节点暴增，需要删除创建的持久化顺序节点
                    // .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath(pathPrefix);
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
